/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package hivInteractions;

import java.io.BufferedWriter;
import java.io.File;
import java.io.IOException;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.TreeMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import ontology.HivProt;
import ontology.InteractionType;
import ontology.InteractionVerb;
import ontology.OntologyReader;
import ontology.ParentInteraction;
import ontology.Polarity;
import units.CellType;
import units.MonkeyType;
import utils.FileUtils;
import utils.Handle;

/**
 *
 * @author jamie
 */
public class MakeMainHivNetwork {

    private File outFile_edges = new File("/Users/jamie/Dropbox/monkeys/hivInteractions/network/edges.txt");
    private File outFile_nodes = new File("/Users/jamie/Dropbox/monkeys/hivInteractions/network/nodes.txt");
    private HashMap<String, String> nodeGroup = new HashMap<String, String>();

    public MakeMainHivNetwork() {
        try {
            outputEdges();
            outputNodes();
        } catch (IOException ex) {
            Logger.getLogger(MakeMainHivNetwork.class.getName()).log(Level.SEVERE, null, ex);
        }

    }

    private void outputEdges() throws IOException {
        Handle handle = Handle.getConnectedHandle("monkeys");
        String sql;
        sql = "select distinct name_1, interaction, symbol from hiv_interactions.hiv_interactions t1, probeIdLookup t2, ncbi.gene_info t3 where  gId_1!='155807' and t1.gId_2=t2.gId and t1.gId_2=t3.gId order by name_1, gId_2";
        ResultSet rs = handle.runSQLquery(sql);
        HashMap<String, Edge> edges = new HashMap<String, Edge>();
        try {
            while (rs.next()) {
                String hivProt = rs.getString("name_1");
                InteractionVerb verb = InteractionVerb.getInteractionVerbByDescription(rs.getString("interaction"));
                String humanProt = rs.getString("symbol");
                if (!edges.containsKey(hivProt + ":" + humanProt)) {
                    edges.put(hivProt + ":" + humanProt, new Edge(hivProt, humanProt));
                    if (nodeGroup.containsKey(humanProt)) {
                        nodeGroup.put(humanProt, nodeGroup.get(humanProt) + "_" + hivProt + "_");
                    } else {
                        nodeGroup.put(humanProt, hivProt + "_");
                    }
                }
                edges.get(hivProt + ":" + humanProt).getVerbs().add(verb);

            }
            rs.close();
        } catch (SQLException ex) {
            Logger.getLogger(MakeMainHivNetwork.class.getName()).log(Level.SEVERE, null, ex);
        }
        BufferedWriter writer = FileUtils.getBufferedWriter(outFile_edges);
        writer.append("hivProt\thumanProt\tdirect\tstim\n");
        for (Edge e : edges.values()) {
            writer.append(e.getHivProt() + "\t" + e.getHumanProt() + "\t" + e.hasDirectInteraction() + "\t" + e.getStimulatoryIndex() + "\n");
        }
        writer.close();
        handle.closeConnection();
    }

    private HashSet<String> getDeGenes() {
        Handle handle = Handle.getConnectedHandle("monkeys");
        String sql;
        sql = "select distinct t4.symbol from probeIdLookup t2, differentialExpression t3, ncbi.gene_info t4 where timePoint>0 and t2.gId=t4.gId and t2.probeId=t3.probeId and pValue>0.1";
        HashSet<String> hash = new HashSet<String>();
        ResultSet rs = handle.runSQLquery(sql);
        try {
            while (rs.next()) {
                hash.add(rs.getString("t4.symbol"));
            }
            rs.close();
        } catch (SQLException ex) {
            Logger.getLogger(MakeMainHivNetwork.class.getName()).log(Level.SEVERE, null, ex);
        }
        handle.closeConnection();
        return hash;
    }

    private void outputNodes() throws IOException {
        Handle handle = Handle.getConnectedHandle("monkeys");
        String sql;

        sql = "select distinct t4.symbol from hiv_interactions.hiv_interactions t1, probeIdLookup t2, ncbi.gene_info t4 where  gId_1!='155807' and t1.gId_2=t2.gId and t2.gId=t4.gId order by symbol";
        HashSet<String> keepers = getDeGenes();

        ResultSet rs = handle.runSQLquery(sql);

        TreeMap<String, Node> nodes = new TreeMap<String, Node>();
        try {
            while (rs.next()) {
                String symbol = rs.getString("symbol");
                if (!nodes.containsKey(symbol)) {
                    Node n = new Node(rs.getString("symbol"), "human");
                    nodes.put(n.getId(), n);
                }

                sql = "select distinct t3.monkeyType, t3.cellType, t3.timePoint, t3.pValue, t3.logExp from probeIdLookup t2, differentialExpression t3, ncbi.gene_info t4 where timePoint>0 and t2.gId=t4.gId and t2.probeId=t3.probeId and pValue>0.1 and t4.symbol='" + symbol + "'";
                ResultSet rs2 = handle.runSQLquery(sql);
                while (rs2.next()) {
                    MonkeyType mt = MonkeyType.valueOf(rs2.getString("t3.monkeyType"));
                    CellType ct = CellType.valueOf(rs2.getString("cellType"));
                    int timePoint = rs2.getInt("timePoint");
                    double logExp = rs2.getDouble("logExp");
                    double pValue = rs2.getDouble("pValue");
                    Node n = nodes.get(symbol);
                    String source = mt.name() + ct.name() + "_" + timePoint;
                    if (!n.getExpressionMap().containsKey(source)) {
                        n.getExpressionMap().put(source, logExp);
                        n.getpValues().put(source, pValue);
                    } else {
                        if (n.getpValues().get(source) > pValue) {
                            n.getExpressionMap().put(source, logExp);
                            n.getpValues().put(source, pValue);
                        }
                    }
                }
                rs2.close();
            }
            rs.close();
        } catch (SQLException ex) {
            Logger.getLogger(MakeMainHivNetwork.class.getName()).log(Level.SEVERE, null, ex);
        }
        sql = "select distinct t1.name_1 from hiv_interactions.hiv_interactions t1, probeIdLookup t2 where t1.gId_2=t2.gId and gId_1!='155807' order by name_1";
        ResultSet rs3 = handle.runSQLquery(sql);
        try {
            while (rs3.next()) {
                String hivProt = rs3.getString("name_1");
                Node n = new Node(hivProt, "hiv");
                nodes.put(n.getId(), n);
                nodeGroup.put(n.getId(), "is_" + n.getId());
            }
            rs3.close();
        } catch (SQLException ex) {
            Logger.getLogger(MakeMainHivNetwork.class.getName()).log(Level.SEVERE, null, ex);
        }

        BufferedWriter writer = FileUtils.getBufferedWriter(outFile_nodes);
        int[] timePoints = {1, 6, 14, 28, 65, 115, 574, 610};

        StringBuffer buffer = new StringBuffer();
        buffer.append("id\torganism\tkeep\tgroup\t");
        for (int timePoint : timePoints) {
            for (MonkeyType mt : MonkeyType.values()) {
                for (CellType ct : CellType.values()) {
                    buffer.append("de_" + mt.name() + ct.name() + "_" + timePoint + "\t");
                    buffer.append("fc_" + mt.name() + ct.name() + "_" + timePoint + "\t");
                    buffer.append("direction_" + mt.name() + ct.name() + "_" + timePoint + "\t");
                    buffer.append("colour_" + mt.name() + ct.name() + "_" + timePoint + "\t");

                }
            }
        }
        writer.append(buffer.toString().trim() + "\n");


        for (Node n : nodes.values()) {
            buffer = new StringBuffer();
            boolean keep = keepers.contains(n.getId());
            if (nodeGroup.containsKey(n.getId())) {
                buffer.append(n.getId() + "\t" + n.getOrganism() + "\t" + keep + "\t" +nodeGroup.get(n.getId())+"\t");

                for (int timePoint : timePoints) {
                    for (MonkeyType mt : MonkeyType.values()) {
                        for (CellType ct : CellType.values()) {
                            String key = mt.name() + ct.name() + "_" + timePoint;
                            if (n.getExpressionMap().containsKey(key)) {
                                String direction = "none";
                                if (n.getExpressionMap().get(key) < 0) {
                                    direction = "down";
                                } else if (n.getExpressionMap().get(key) > 0) {
                                    direction = "up";
                                }
                                buffer.append("yes\t" + Math.abs(n.getExpressionMap().get(key)) + "\t" + direction + "\tthird\t");

                            } else {
                                String colour = "first";
                                double exp = 10.0;
                                if (!n.getOrganism().equals("hiv")) {
                                    colour = "second";
                                    exp = 0;
                                }
                                buffer.append("no\t" + exp + "\tnone\t" + colour + "\t");
                            }

                        }
                    }
                }
                writer.append(buffer.toString().trim() + "\n");
            }
        }
        writer.close();
    }

    private class Edge {

        private String hivProt;
        private List<InteractionVerb> verbs = new ArrayList<InteractionVerb>();
        private String humanProt;

        public String getHivProt() {
            return hivProt;
        }

        public String getHumanProt() {
            return humanProt;
        }

        public Edge(String hivProt, String humanProt) {
            this.hivProt = hivProt;
            this.humanProt = humanProt;
        }

        public List<InteractionVerb> getVerbs() {
            return verbs;
        }

        public boolean hasDirectInteraction() {
            for (InteractionVerb verb : verbs) {
                if (verb.isPhysical()) {
                    return true;
                }
            }
            return false;
        }

        public int getStimulatoryIndex() {
            boolean agonistic = false;
            boolean antagonistic = false;
            for (InteractionVerb verb : verbs) {
                if (verb.getParent().equals(ParentInteraction.GENE_REGULATION) || verb.getParent().equals(ParentInteraction.PROTEIN_REGULATION)) {
                    if (verb.getPolarity().equals(Polarity.NEGATIVE)) {
                        antagonistic = true;
                    } else if (verb.getPolarity().equals(Polarity.POSITIVE)) {
                        agonistic = true;
                    }
                }
            }
            if (agonistic && antagonistic) {
                return 2;
            }
            if (agonistic) {
                return 1;
            }
            if (antagonistic) {
                return -1;
            }
            return 0;
        }
    }

    private class Node {

        private String id;
        private String organism;
        private HashMap<String, Double> pValues = new HashMap<String, Double>();
        private HashMap<String, Double> logExpMap = new HashMap<String, Double>();

        public Node(String id, String organism) {
            this.id = id;
            this.organism = organism;
        }

        public String getOrganism() {
            return organism;
        }

        public String getId() {
            return id;
        }
        private TreeMap<String, Double> expressionMap = new TreeMap<String, Double>();

        public TreeMap<String, Double> getExpressionMap() {
            return expressionMap;
        }

        public HashMap<String, Double> getpValues() {
            return pValues;
        }

        public HashMap<String, Double> getLogExpMap() {
            return logExpMap;
        }

        @Override
        public boolean equals(Object obj) {
            if (obj == null) {
                return false;
            }
            if (getClass() != obj.getClass()) {
                return false;
            }
            final Node other = (Node) obj;
            if ((this.id == null) ? (other.id != null) : !this.id.equals(other.id)) {
                return false;
            }
            if ((this.organism == null) ? (other.organism != null) : !this.organism.equals(other.organism)) {
                return false;
            }
            return true;
        }

        @Override
        public int hashCode() {
            int hash = 7;
            hash = 23 * hash + (this.id != null ? this.id.hashCode() : 0);
            hash = 23 * hash + (this.organism != null ? this.organism.hashCode() : 0);
            return hash;
        }
    }
}
